package com.myssm.mybatis.org.apache.ibatis.session;

import com.myssm.mybatis.org.apache.ibatis.configuration.Configuration;
import com.myssm.mybatis.org.apache.ibatis.configuration.MappedStatement;
import com.myssm.mybatis.org.apache.ibatis.configuration.SqlCommandType;
import com.myssm.mybatis.org.apache.ibatis.executor.SimpleExecutor;

import java.lang.reflect.*;
import java.util.List;

public class DefaultSqlSession implements SqlSession{

    private final Configuration configuration;

    public DefaultSqlSession(Configuration configuration){
        this.configuration=configuration;
    }

    //使用jdk动态代理给xxxMapper接口生成代理类对象
    @Override
    public <E> E getMapper(Class<E> mapperClass) {

        //jdk动态代理给xxxMapper接口生成代理类对象
        Object proxyInstance = Proxy.newProxyInstance(mapperClass.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //方法名
                String methodName = method.getName();
                //接口全类名
                String className = method.getDeclaringClass().getName();
                //拼接configuration中mappedStatements的Map的key
                String statementId = className + "." + methodName;
                //获取方法返回值类型
                Type genericReturnType = method.getGenericReturnType();
                //获取对应的MappedStatement
                MappedStatement mappedStatement = configuration.getMappedStatements().get(statementId);

                //为增删改
                if (mappedStatement.getSqlCommandType()== SqlCommandType.INSERT) {
                    return insert(statementId, args);
                } else if (mappedStatement.getSqlCommandType()==SqlCommandType.UPDATE) {
                    return update(statementId, args);
                } else if (mappedStatement.getSqlCommandType()==SqlCommandType.DELETE) {
                    return delete(statementId, args);
                }

                //为查询
                if (mappedStatement.getSqlCommandType()==SqlCommandType.SELECT){
                    if (genericReturnType instanceof ParameterizedType) {
                        //有泛型，为查询多条
                        return selectList(statementId, args);
                    } else {
                        //为查询单条
                        return selectOne(statementId, args);
                    }
                }

                throw new RuntimeException(methodName+"不是增删改查方法");

            }
        });

        return (E) proxyInstance;
    }

    @Override
    public <E> List<E> selectList(String statementId, Object... params) throws Exception {
        //todo: 单例executor
        SimpleExecutor simpleExecutor = new SimpleExecutor();
        MappedStatement mappedStatement = configuration.getMappedStatements().get(statementId);
        if (mappedStatement==null){
            throw new RuntimeException("没有对应的mapper方法");
        }
        List<Object> list = simpleExecutor.querry(configuration, mappedStatement, params);
        return (List<E>) list;
    }

    @Override
    public <E> E selectOne(String statementId, Object...  params) throws Exception {
        List<Object> objects = this.selectList(statementId, params);
        if (objects.size()==1){
            return (E) objects.get(0);
        } else if (objects.size()>1) {
            throw new RuntimeException("查询结果不为单个");
        }else {
            throw new RuntimeException("查询结果为空");
        }
    }

    @Override
    public int insert(String statementId, Object...  params) throws Exception {
        SimpleExecutor simpleExecutor = new SimpleExecutor();
        MappedStatement mappedStatement = configuration.getMappedStatements().get(statementId);
        if (mappedStatement==null){
            throw new RuntimeException("没有对应的mapper方法");
        }
        List<Integer> list = simpleExecutor.querry(configuration, mappedStatement, params);
        return list.get(0);
    }

    @Override
    public int update(String statementId, Object... params) throws Exception {
        SimpleExecutor simpleExecutor = new SimpleExecutor();
        MappedStatement mappedStatement = configuration.getMappedStatements().get(statementId);
        if (mappedStatement==null){
            throw new RuntimeException("没有对应的mapper方法");
        }
        List<Integer> list = simpleExecutor.querry(configuration, mappedStatement, params);
        return list.get(0);
    }

    @Override
    public int delete(String statementId, Object... params) throws Exception {
        SimpleExecutor simpleExecutor = new SimpleExecutor();
        MappedStatement mappedStatement = configuration.getMappedStatements().get(statementId);
        if (mappedStatement==null){
            throw new RuntimeException("没有对应的mapper方法");
        }
        List<Integer> list = simpleExecutor.querry(configuration, mappedStatement, params);
        return list.get(0);
    }
}
